/**
 * @file   RestrictionOperator.cpp
 * @author HirasawaYui <yui@Ubuntu18-04>
 * @date   Tue Oct 20 21:31:36 2020
 * 
 * @brief  2 kinds of restriction operator for MultigridSolver, 2D case
 * 
 * 
 */
#include "RestrictionOperator.h"

RestrictionOperator::RestrictionOperator()
{
}

RestrictionOperator::~RestrictionOperator()
{

}

void RestrictionOperator::SetInput(std::vector<double> a)
{
    _Input = a;
}

void RestrictionOperator::SetSdLen(int OldSdLen)
{
    _OldSdLen = OldSdLen;
    _NewSdLen = (OldSdLen + 1) / 2;
    _Output = std::vector<double>(_NewSdLen * _NewSdLen, 0); 
}

int RestrictionOperator::CortoIdx(int i, int j, int SdLen)
{
    return (i * SdLen + j);
}

std::vector<double> RestrictionOperator::ReturnOutput()
{
    return _Output;
}

void RestrictionOperator::restrict()
{
    std::cerr << "Restriction Error!" << std::endl;
    exit(-1);
}

void InjectionRestriction::restrict()
{
    for (int i = 0; i < _NewSdLen; i++)
	for (int j = 0; j < _NewSdLen; j++)
		_Output[CortoIdx(i, j, _NewSdLen)] = _Input[CortoIdx(2*i, 2*j, _OldSdLen)];
}

void FullWeightingRestriction::restrict()
{
    for (int i = 0; i < _NewSdLen; i++)
	for (int j = 0; j < _NewSdLen; j++)
	{
	    if (i == 0 || i == _NewSdLen-1 || j == 0 || j == _NewSdLen-1)
		_Output[CortoIdx(i, j, _NewSdLen)] = _Input[CortoIdx(2*i, 2*j, _OldSdLen)];
	    else
	    {
		_Output[CortoIdx(i, j, _NewSdLen)] = (_Input[CortoIdx(2*i-1, 2*j-1, _OldSdLen)] + _Input[CortoIdx(2*i-1, 2*j+1, _OldSdLen)]
						      + _Input[CortoIdx(2*i+1, 2*j-1, _OldSdLen)] + _Input[CortoIdx(2*i+1, 2*j+1, _OldSdLen)]
						      + 2*(_Input[CortoIdx(2*i, 2*j-1, _OldSdLen)] + _Input[CortoIdx(2*i, 2*j+1, _OldSdLen)]
							   + _Input[CortoIdx(2*i-1, 2*j, _OldSdLen)] + _Input[CortoIdx(2*i+1, 2*j, _OldSdLen)])
						      + 4*_Input[CortoIdx(2*i, 2*j, _OldSdLen)])/16.0;
	    }
	}
}
/**void FullWeightingRestriction::restrict()
{
	for(int i = 0;i < _NewSdLen; i++)
		for(int j = 0;j < _NewSdLen; j++)
		{
			if(i == 0 || i == _NewSdLen-1 || j == 0 || j == _NewSdLen-1)
			{
				if(i == 0 && j == 0)//左下角
				{
					int u0 = CortoIdx(i,j,_NewSdLen);
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i,2 * j + 1,_OldSdLen);
					int v3 = CortoIdx(2 * i + 1,2 * j,_OldSdLen);
					int v4 = CortoIdx(2 * i + 1,2 * j + 1,_OldSdLen);
					_Output[u0] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3]) + 0.25 * _Input[v4];
				}
				else if(i == 0 && j == _NewSdLen - 1)//右下角
				{
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i,2 * j - 1,_OldSdLen);
					int v3 = CortoIdx(2 * i + 1,2 * j,_OldSdLen);
					int v4 = CortoIdx(2 * i + 1,2 * j - 1,_OldSdLen);
					_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3]) + 0.25 * _Input[v4];
				}
				else if(i == _NewSdLen - 1 && j == 0)//左上角
				{
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i - 1,2 * j ,_OldSdLen);
					int v3 = CortoIdx(2 * i,2 * j + 1,_OldSdLen);
					int v4 = CortoIdx(2 * i - 1,2 * j + 1,_OldSdLen);
					_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3]) + 0.25 * _Input[v4];
				}
				else if(i == _NewSdLen - 1 && j == _NewSdLen - 1)//右上角
				{
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i,2 * j - 1,_OldSdLen);
					int v3 = CortoIdx(2 * i - 1,2 * j,_OldSdLen);
					int v4 = CortoIdx(2 * i - 1,2 * j - 1,_OldSdLen);
					_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3]) + 0.25 * _Input[v4];
				}
				else if(i == 0)//下边界上（非左右角）
				{
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i,2 * j - 1,_OldSdLen);
					int v3 = CortoIdx(2 * i,2 * j + 1,_OldSdLen);
					int v4 = CortoIdx(2 * i + 1,2 * j,_OldSdLen);

					int v5 = CortoIdx(2 * i + 1,2 * j - 1,_OldSdLen);
					int v6 = CortoIdx(2 * i + 1,2 * j + 1,_OldSdLen);
					_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3] + _Input[v4]) + 0.25 * (_Input[v5] + _Input[v6]);
				}
				else if(i == _NewSdLen - 1)//上边界上（非左右角）
				{
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i,2 * j - 1,_OldSdLen);
					int v3 = CortoIdx(2 * i,2 * j + 1,_OldSdLen);
					int v4 = CortoIdx(2 * i - 1,2 * j,_OldSdLen);

					int v5 = CortoIdx(2 * i - 1,2 * j - 1,_OldSdLen);
					int v6 = CortoIdx(2 * i - 1,2 * j + 1,_OldSdLen);
					_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3] + _Input[v4]) + 0.25 * (_Input[v5] + _Input[v6]);
				}
				else if(j == 0)
				{
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i - 1,2 * j,_OldSdLen);
					int v3 = CortoIdx(2 * i + 1,2 * j,_OldSdLen);
					int v4 = CortoIdx(2 * i,2 * j + 1,_OldSdLen);

					int v5 = CortoIdx(2 * i - 1,2 * j + 1,_OldSdLen);
					int v6 = CortoIdx(2 * i + 1,2 * j + 1,_OldSdLen);
					_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3] + _Input[v4]) + 0.25 * (_Input[v5] + _Input[v6]);
				}
				else if(j == _NewSdLen - 1)
				{
					int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
					int v2 = CortoIdx(2 * i - 1,2 * j,_OldSdLen);
					int v3 = CortoIdx(2 * i + 1,2 * j,_OldSdLen);
					int v4 = CortoIdx(2 * i,2 * j - 1,_OldSdLen);

					int v5 = CortoIdx(2 * i - 1,2 * j - 1,_OldSdLen);
					int v6 = CortoIdx(2 * i + 1,2 * j - 1,_OldSdLen);
					_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3] + _Input[v4]) + 0.25 * (_Input[v5] + _Input[v6]);
				}
			}
		else
			{
				int v1 = CortoIdx(2 * i,2 * j,_OldSdLen);
				int v2 = CortoIdx(2 * i - 1,2 * j,_OldSdLen);
				int v3 = CortoIdx(2 * i + 1,2 * j,_OldSdLen);
				int v4 = CortoIdx(2 * i,2 * j - 1,_OldSdLen);
				int v5 = CortoIdx(2 * i,2 * j + 1,_OldSdLen);

				int v6 = CortoIdx(2 * i - 1,2 * j - 1,_OldSdLen);
				int v7 = CortoIdx(2 * i + 1,2 * j - 1,_OldSdLen);
				int v8 = CortoIdx(2 * i - 1,2 * j + 1,_OldSdLen);
				int v9 = CortoIdx(2 * i + 1,2 * j + 1,_OldSdLen);
				_Output[CortoIdx(i,j,_NewSdLen)] = _Input[v1] + 0.5 * (_Input[v2] + _Input[v3] + _Input[v4] + _Input[v5]) + 0.25 * (_Input[v6] + _Input[v7] + _Input[v8] + _Input[v9]);
			}
		}
}**/
